package com.devil.assistant.controller;

import com.devil.assistant.advisor.LoggingAdvisor;
import com.devil.assistant.tools.AssistantTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.time.LocalDate;

/**
 * 智能助手前端交互控制器
 *
 * <p>本控制器作为AI助手系统的入口端点，提供基于SSE（Server-Sent Events）的流式对话接口，
 * 集成多模态工具调用、上下文记忆、向量检索等核心能力。</p>
 *
 * <h3>核心特性：</h3>
 * <ul>
 *   <li>支持持续对话的上下文记忆管理</li>
 *   <li>集成RAG（检索增强生成）能力</li>
 *   <li>多工具自动编排调用（本地工具+MCP协议工具）</li>
 *   <li>可观测性增强（日志追踪、监控埋点）</li>
 * </ul>
 *
 * @author Devil
 * @version 1.0
 * @see ChatClient 聊天客户端核心引擎
 * @see VectorStore 向量检索组件
 * @since 2025/4/11
 */
@CrossOrigin
@RestController
@RequestMapping("/assistant")
public class AssistantController {

    private final ChatClient chatClient;

    /**
     * 聊天客户端构造器（组件装配核心）
     *
     * <p>通过Spring AI的ChatClientBuilder构建具备以下能力的聊天引擎：</p>
     * <ol>
     *   <li><strong>系统角色定义</strong>：设定助手的性格特征和行为规范</li>
     *   <li><strong>对话拦截链</strong>：
     *     <ul>
     *       <li>PromptChatMemoryAdvisor：上下文记忆管理</li>
     *       <li>LoggingAdvisor：请求/响应日志追踪</li>
     *     </ul>
     *   </li>
     *   <li><strong>工具集成</strong>：
     *     <ul>
     *       <li>AssistantTools：本地预置工具集</li>
     *       <li>mcpTools：MCP协议远程工具</li>
     *     </ul>
     *   </li>
     * </ol>
     *
     * @param chatClientBuilder 聊天客户端构建器（Spring AI自动装配）
     * @param vectorStore       向量存储组件（用于RAG检索）
     * @param chatMemory        对话记忆管理组件
     * @param assistantTools    本地工具集合（文章处理/数据分析等）
     * @param mcpTools          MCP协议工具提供者（动态工具发现）
     */
    public AssistantController(ChatClient.Builder chatClientBuilder,
                               VectorStore vectorStore,
                               ChatMemory chatMemory,
                               AssistantTools assistantTools,
                               ToolCallbackProvider mcpTools) {
        this.chatClient = chatClientBuilder
                .defaultSystem("""
                        您是“Devil”的助手。请以友好、乐于助人且愉快的方式来回复。
                        您正在通过在线聊天系统与客户互动。
                        在获取文章信息之前，您必须始终从用户处获取以下信息：文章标题。
                        如果找到了多篇文章，返回文章标题和发布时间给客户。
                        请讲中文。
                        """)
                .defaultAdvisors(
                        new PromptChatMemoryAdvisor(chatMemory), // 上下文记忆管理
                        new LoggingAdvisor())                     // 日志追踪
                .defaultTools(assistantTools)                    // 本地工具注册
                .defaultTools(mcpTools)                          // MCP协议工具
                .build();
    }

    @Autowired
    private VectorStore vectorStore;  // 向量存储组件（用于相似性检索）

    /**
     * 流式对话接口（SSE协议）
     *
     * <p>技术实现要点：</p>
     * <ul>
     *   <li>采用响应式流（Flux）处理持续对话</li>
     *   <li>动态注入当前日期作为系统参数</li>
     *   <li>集成问答建议顾问（基于向量检索的RAG）</li>
     *   <li>响应流结尾追加[complete]作为结束标识</li>
     * </ul>
     *
     * @param message 用户输入消息（默认示例："讲个笑话"）
     * @return SSE事件流（text/event-stream）
     * @apiNote 示例请求：GET /assistant/chat?message=什么是Spring AI
     */
    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStreamAsString(
            @RequestParam(value = "message", defaultValue = "讲个笑话") String message) {

        return chatClient.prompt()
                .system(spec -> spec.param("current_date", LocalDate.now().toString())) // 注入时间上下文
                .advisors(spec -> spec.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)) // 记忆检索窗口
                .user(message)  // 用户输入
                .advisors(new QuestionAnswerAdvisor(vectorStore,  // RAG增强
                        SearchRequest.builder().query(message).build()))
                .stream()
                .content()
                .concatWith(Flux.just("[complete]")); // 流结束标识
    }
}
